package com.qingzhou.log.aspect;

import com.alibaba.fastjson.JSON;
import com.qingzhou.log.annotation.SysLogAnno;
import com.qingzhou.log.pojo.SysLog;
import com.qingzhou.log.service.SysLogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/***
 * @author: huoming
 * @note: 日志切面
 * @intruduce: 切面父类，包含切面的主要功能
 */
@Aspect
public abstract class BaseLogAspect implements InitializingBean{
    @Autowired
    AspectRegistry aspectRegistry;

    /***
     * 匹配规则1：类上匹配
     */
    @Pointcut("@within(com.qingzhou.log.annotation.SysLogAnno)")
    public void log1(){}

    /***
     * 匹配规则2：方法上匹配
     */
    @Pointcut("@annotation(com.qingzhou.log.annotation.SysLogAnno)")
    public void log2(){}

    /***
     * 匹配规则1，2
     */
    @Pointcut("log1() || log2()")
    public void log(){}

    public void afterPropertiesSet() throws Exception {
        this.aspectRegistry.register(this);
    }

    /***
     * 日志记录
     */
    @Around("log()")
    public Object writeSysLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object returnValue=null;
        Date before=new Date();
        returnValue= proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        writeLogToDatabase(before,returnValue,proceedingJoinPoint);
        return returnValue;
    }
    private void writeLogToDatabase(Date before,Object returnValue,JoinPoint joinPoint){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request=null;
        String ipAddress=null;
        String remark="";
        String username=null;
        if(attributes!=null){
            request=attributes.getRequest();
            if (request!=null){
                ipAddress=request.getRemoteAddr();
                username=parseUsername(request);
            }
        }
        Class requestClass=joinPoint.getSignature().getDeclaringType();
        MethodSignature methodSignature=(MethodSignature)joinPoint.getSignature();
        Method method=methodSignature.getMethod();
        //从Swagger注解中得到操作
        String userOperation=(requestClass.getAnnotation(Api.class)==null?"":((Api)requestClass.getAnnotation(Api.class)).value())+"==>"+(method.getAnnotation(ApiOperation.class)==null?"":method.getAnnotation(ApiOperation.class).value());
        //计算响应时间
        Long responseTime=new Date().getTime()-before.getTime();
        //记录建立时间
        Date createTime=new Date();
        //得到请求方法名
        String requestMethod=joinPoint.getSignature().getName();
        //解析得到请求参数列表
        String requestArgs=parseRequestArgs(joinPoint);
        //记录备注
        if(method.getAnnotation(SysLogAnno.class)==null){
            remark=((SysLogAnno)requestClass.getAnnotation(SysLogAnno.class)).sensitive()?"sensitive operation":"";
        }else{
            remark=method.getAnnotation(SysLogAnno.class).sensitive()?"sensitive operation":"";
        }
        //保存
        SysLog sysLog=new SysLog(username,userOperation,responseTime,requestMethod,requestArgs,ipAddress,createTime,returnValue.toString(),remark);
        aspectRegistry.updateSysLog(this,sysLog);
    }

    /***
     * 解析用户名
     */
    public abstract String parseUsername(HttpServletRequest request);

    /***
     * 解析请求参数
     */
    private String parseRequestArgs(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        List<Object> argList = new ArrayList<Object>();
        for (Object arg : args) {
            if (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
                continue;
            }
            argList.add(arg);
        }
        return JSON.toJSONString(argList);
    }

}
